/**
 * 缓存服务
 */
export interface LocalCache<T> {
  // 缓存数据
  data: T
  // 创建时间
  createTime: number
  // 结束时间
  lifeTime: number
}

/**
 * 本地缓存
 */
export class LocalStorageCache<T> {
  // 当前缓存key
  private readonly currentKey: string
  // 缓存保存时间
  private limit: number
  // 是否自动刷新缓存
  private readonly autoFresh: boolean
  // 自动刷新缓存方法
  private readonly refreshFun: Function
  // 调用自动刷新缓存方法后，对数据进行进一步处理的方法
  private readonly afterRefresh = (data: unknown) => <T>data
  // 老值
  private oldValue: T | null = null
  /**
   * 构造器
   * @param key 缓存key
   * @param limit 缓存时间
   * @param autoFresh 是否自动刷新
   * @param fun 刷新缓存方法
   * @param value 初始值
   */
  constructor(
    key: string = '',
    limit: number = 1000 * 60 * 60 * 24 * 1,
    autoFresh: boolean = false,
    fun: Function = () => null,
    afterRefresh = (data: unknown) => <T>data,
    value?: T,
  ) {
    this.currentKey = key
    this.limit = limit
    this.refreshFun = fun
    this.autoFresh = autoFresh
    this.afterRefresh = afterRefresh
    if (value) {
      this.set(value)
    }
  }
  /**
   * 设置缓存
   * @param data 数据
   * @param time 期限 默认一天
   */
  set(data: T, time: number = this.limit): boolean {
    const key = this.check()
    this.oldValue = data
    this.limit = time
    const storage: LocalCache<T> = {
      data,
      createTime: Date.now(),
      lifeTime: time,
    }
    localStorage.setItem(key, JSON.stringify(storage))
    return true
  }
  /**
   * 获取数据
   */
  async get(): Promise<T | null> {
    const key = this.check()
    let res = localStorage.getItem(key)
    // key值不存在，且开启自动刷新
    if (!res && this.autoFresh) {
      return await this.refresh()
    }
    if (!res) {
      return null
    }
    const data = JSON.parse(res) as unknown as LocalCache<T>
    // 当前时间 - 存入时间 < 过期时间
    if (Date.now() - data.createTime <= data.lifeTime) {
      return <T>data.data
    } else {
      // 过期自动删除该缓存
      if (!this.autoFresh) {
        this.delete()
        return null
      }
      // 刷新缓存同时返回原数据
      return await this.refresh()
    }
  }
  /**
   * 删除数据
   * @param key 键名
   */
  delete() {
    this.check()
    localStorage.removeItem(this.currentKey)
  }

  /**
   * 过期刷新缓存的方法
   */
  async refresh(): Promise<T | null> {
    this.check()
    if (this.refreshFun && this.autoFresh) {
      const data = await this.refreshFun.apply(this, arguments)
      // 是否是promise
      if (data instanceof Promise) {
        await data
          .then((data) => {
            console.info(`The cache key ${this.currentKey} had be refreshed!`)
            this.set(this.afterRefresh(data))
            return <T>data
          })
          .catch(() => {
            // 如果出现错误，直接返回原值
            return this.oldValue
          })
        return this.oldValue
      } else {
        // 如果不是promise则直接将数据获取出来
        this.set(this.afterRefresh(data))
        return <T>data
      }
    } else {
      return null
    }
  }

  /**
   * 检查键是否存在
   * @param key
   * @private
   */
  private check(): string {
    if (this.currentKey == '') {
      throw Error(`the cache key is null!`)
    }
    return this.currentKey
  }
}
